package com.example.suuu.tools.log;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;

@Aspect
@Component
@Slf4j
public class LogPrintAspect {
    /** 计算操作消耗时间 */
    private static final ThreadLocal<Long> TIME_THREADLOCAL = new ThreadLocal<Long>();

//    @Pointcut("@annotation(com.example.suuu.tools.log.LogPrint)")
//    //@Pointcut("execution(* com.example.suuu.project.*.controller.*.*(..))")
//    public void logPrint() {
//    }

    /**
     * 请求完成后执行
     */
    @AfterReturning(pointcut = "@annotation(com.example.suuu.tools.log.LogPrint)",returning = "jsonResult")
    public void doAfterReturnibng(JoinPoint joinPoint, Object jsonResult) throws Throwable {
        TIME_THREADLOCAL.set(System.currentTimeMillis());
        log.info("=========================================== 执行操作日志 ===========================================");
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        String methodDescription = getAspectLogDescription(joinPoint);
        // 打印请求 url
        log.info("URL            : {}", request.getRequestURL().toString());
        // 打印描述信息
        log.info("描述信息    : {}", methodDescription);
        // 打印 Http method
        log.info("请求方式    : {}", request.getMethod());
        // 打印调用 controller 的全路径以及执行方法
        log.info("执行方法   : {}.{}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName());
        // 打印请求的 IP
        log.info("IP             : {}", request.getRemoteAddr());
        // 打印请求入参
        log.info("请求参数   : {}", getParams(joinPoint));
        log.info("请求返回   : {}", JSON.toJSONString(jsonResult));
        log.info("请求时间   : {}", System.currentTimeMillis() - TIME_THREADLOCAL.get());
        log.info("=========================================== 结束操作日志 ===========================================");
        TIME_THREADLOCAL.remove();
    }

    /**
     * 在切点之前
     * @param joinPoint
     * @throws Throwable
     */
//    @Before("logPrint()")
//    public void doBefore(JoinPoint joinPoint) throws Throwable {
//        log.info("=========================================== 进入请求 ===========================================");
//        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
//        HttpServletRequest request = attributes.getRequest();
//        String methodDescription = getAspectLogDescription(joinPoint);
//        // 打印请求 url
//        log.info("URL            : {}", request.getRequestURL().toString());
//        // 打印描述信息
//        log.info("描述信息    : {}", methodDescription);
//        // 打印 Http method
//        log.info("请求方式    : {}", request.getMethod());
//        // 打印调用 controller 的全路径以及执行方法
//        log.info("执行方法   : {}.{}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName());
//        // 打印请求的 IP
//        log.info("IP             : {}", request.getRemoteAddr());
//        // 打印请求入参
//        log.info("请求参数   : {}", getParams(joinPoint));
//    }

    /**
     * 在切点之后
     */
//    @After("logPrint()")
//    public void doAfter() throws Throwable {
//        // 接口结束后换行，方便分割查看
//        log.info("=========================================== 请求完成 ===========================================");
//    }

    /**
     * 环绕
     */
//    @Around("logPrint()")
//    public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
//        long startTime = System.currentTimeMillis();
//        Object result = proceedingJoinPoint.proceed();
//        // 打印出参
//        log.info("返回参数  : {}", JSONObject.toJSONString(result));
//        // 执行耗时
//        log.info("响应时间 : {} ms", System.currentTimeMillis() - startTime);
//        return result;
//    }


    public String getAspectLogDescription(JoinPoint joinPoint)
            throws Exception {
        String targetName = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        Object[] arguments = joinPoint.getArgs();
        Class targetClass = Class.forName(targetName);
        Method[] methods = targetClass.getMethods();
        StringBuilder description = new StringBuilder("");
        for (Method method : methods) {
            if (method.getName().equals(methodName)) {
                Class[] clazzs = method.getParameterTypes();
                if (clazzs.length == arguments.length) {
                    description.append(method.getAnnotation(com.example.suuu.tools.log.LogPrint.class).value());
                    break;
                }
            }
        }
        return description.toString();
    }

    private String getParams(JoinPoint joinPoint) {
        String params = "";
        if (joinPoint.getArgs() != null && joinPoint.getArgs().length > 0) {
            for (int i = 0; i < joinPoint.getArgs().length; i++) {
                Object arg = joinPoint.getArgs()[i];
                if ((arg instanceof HttpServletResponse) || (arg instanceof HttpServletRequest)
                        || (arg instanceof MultipartFile) || (arg instanceof MultipartFile[])) {
                    continue;
                }
                try {
                    params += JSONObject.toJSONString(joinPoint.getArgs()[i]);
                } catch (Exception e1) {
                    log.error(e1.getMessage());
                }
            }
        }
        return params;
    }

}

